package com.io.nettyflow.serverHandler;

import com.io.protocol.LengthConstants;
import com.io.util.DecodeBaseModel;
import com.io.util.NettyUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * Created by yangyx on 2016/7/21.
 */
public class VtsDecoderHandler extends ByteToMessageDecoder {

    private boolean decodingState=false;//找到包头开始算解码
    private int packageContentlen =0; //包的总长度

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        Object decoded=mydecode(byteBuf);
        if(decoded != null){
            list.add(decoded);
        }
    }
    //解析，判断，处理数据
    private Object mydecode(ByteBuf in) {

        if(in.readableBytes()==0){
            return null;
        }
        int packageOffset=0;
        if(!decodingState){
            int startFlageIndex=findStartFlag(in);


            if(startFlageIndex==-1){
                in.skipBytes(in.readableBytes());//正常情况应该是含有包头的，此时没有，忽略。
            }else{
                //处理数据
                decodingState=true;
                if(startFlageIndex>=0){//开始位置必须大于零 //WARN 有的时候可能为零，也就是没有拆包的现象
                    in.skipBytes(startFlageIndex);
                    packageOffset=startFlageIndex;
                }
            }
        }
        if(decodingState){
            //已经找到了头部信息，上面验证不再需要进行
            if(packageContentlen==0){
                if(in.readableBytes()< LengthConstants.PackageHeaderLength+ LengthConstants.PackageSizeLength){
                   return null;
                }
                //默认是大端字节序，若要小段字节序可以
                // in= in.order(ByteOder.LITTLE_ENDIAN);
                int contentLen=in.getUnsignedShort(packageOffset + LengthConstants.PackageHeaderLength);
                packageContentlen= LengthConstants.PackageHeaderLength+ LengthConstants.PackageSizeLength+contentLen;
            }
            if (packageContentlen>= LengthConstants.MinPackageLength){
                //此时已经获取到帧内容长度了，查看可读缓存长度是否够用，不够继续等待，
                if(in.readableBytes()<packageContentlen){
                    return null;
                }
                short crcCal= NettyUtils.calculateCrc(in,packageOffset,packageOffset+packageContentlen-2);
                short crcClaim = in.getShort(packageOffset+packageContentlen-2);
                if(crcCal !=crcClaim){
                    //未知数据源的数据
                    //TODO 此处应该做下日志记录，此处是数据验证
                    inSkipBytes(in);
                    return null;
                }
                int len=packageContentlen;
                decodingState=false;
                packageContentlen=0;
                //TODO 解析传输的对象 暂时返回null
                return DecodeBaseModel.decodemodel(in,len);
            }else{
                //丢弃
                //TODO 此处应该做下日志记录，以便排查问题和预防第三方攻击，后期完善（可以把日志功能放进丢包函数内）
                inSkipBytes(in);
            }
        }
        return null;
    }

    /**
     *缓冲区内部的数据不准确或者说不安全，
     * 服务端无法接受，即跳过该下标数据 注意：并没有重置
     * @param in
     */
    private void inSkipBytes(ByteBuf in) {
        in.skipBytes(packageContentlen);
        decodingState =false;
        packageContentlen=0;
    }

    //查找开始位置
    private int findStartFlag(ByteBuf in) {
        for(int i=in.readerIndex();i<in.writerIndex()-1;i++){
            if (in.getByte(i)== LengthConstants.ThePackageHeader) return i;
            System.out.println("========ByteBuf的开始下标"+i+"，可读长度为=="+in.readableBytes());
        }
        return -1;
    }
}
